package com.cloud.form.api.service.impl;

import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cloud.form.api.bean.FormRepositoryCriteria;
import com.cloud.form.api.entity.FormAssemblyInst;
import com.cloud.form.api.entity.FormDataPush;
import com.cloud.form.api.entity.FormDataSet;
import com.cloud.form.api.entity.FormDef;
import com.cloud.form.api.entity.RepoFormAssemblyInst;
import com.cloud.form.api.entity.RepoFormDataPush;
import com.cloud.form.api.entity.RepoFormDataSet;
import com.cloud.form.api.entity.RepoFormDef;
import com.cloud.form.api.mapper.FormAssemblyInstMapper;
import com.cloud.form.api.mapper.FormDataPushMapper;
import com.cloud.form.api.mapper.FormDataSetMapper;
import com.cloud.form.api.mapper.FormDefMapper;
import com.cloud.form.api.mapper.RepoFormAssemblyInstMapper;
import com.cloud.form.api.mapper.RepoFormDataPushMapper;
import com.cloud.form.api.mapper.RepoFormDataSetMapper;
import com.cloud.form.api.mapper.RepoFormDefMapper;
import com.cloud.form.api.service.FormRepositoryService;
import com.cloud.form.common.utils.WordHelper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import tk.mybatis.mapper.entity.Example;

@Service
@Transactional
public class FormRepositoryServiceImpl implements FormRepositoryService {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private FormDefMapper formDefMapper;

	@Autowired
	private FormAssemblyInstMapper formAssemblyInstMapper;

	@Autowired
	private FormDataSetMapper formDataSetMapper;

	@Autowired
	private FormDataPushMapper formDataPushMapper;

	@Autowired
	private RepoFormDefMapper repoFormDefMapper;

	@Autowired
	private RepoFormDataSetMapper repoFormDataSetMapper;

	@Autowired
	private RepoFormDataPushMapper repoFormDataPushMapper;

	@Autowired
	private RepoFormAssemblyInstMapper repoFormAssemblyInstMapper;

	@Override
	public PageInfo<RepoFormDef> listFormPage(FormRepositoryCriteria criteria) {
		return PageHelper.startPage(criteria.getPageNum(), criteria.getPageSize())
				.doSelectPageInfo(() -> repoFormDefMapper.selectRepoFrom(criteria));
	}

	@Override
	public void pushForm(long id) {
		FormDef def = formDefMapper.selectByPrimaryKey(id);
		RepoFormDef repoDef = new RepoFormDef();
		BeanUtils.copyProperties(def, repoDef);
		repoDef.setFormId(null);
		repoFormDefMapper.insert(repoDef);

		// 数据集
		Example dsExample = new Example(FormDataSet.class);
		Example.Criteria dsCri = dsExample.createCriteria();
		dsCri.andEqualTo("formId", id);
		List<FormDataSet> dSets = formDataSetMapper.selectByExample(dsExample);
		for (FormDataSet ds : dSets) {
			RepoFormDataSet rds = new RepoFormDataSet();
			BeanUtils.copyProperties(ds, rds);
			rds.setDataSetId(null);
			rds.setFormId(repoDef.getFormId());
			repoFormDataSetMapper.insert(rds);
		}
		// 数据推送
		Example dpExample = new Example(FormDataPush.class);
		Example.Criteria dpCri = dpExample.createCriteria();
		dpCri.andEqualTo("formId", id);
		List<FormDataPush> dpSets = formDataPushMapper.selectByExample(dpExample);
		for (FormDataPush dps : dpSets) {
			RepoFormDataPush rdps = new RepoFormDataPush();
			BeanUtils.copyProperties(dps, rdps);
			rdps.setDataPushId(null);
			rdps.setFormId(repoDef.getFormId());
			repoFormDataPushMapper.insert(rdps);
		}

		// 表单控件
		Example assemblyExample = new Example(FormDataPush.class);
		Example.Criteria assemblyCri = assemblyExample.createCriteria();
		assemblyCri.andEqualTo("formId", id);
		List<FormAssemblyInst> insts = formAssemblyInstMapper.selectByExample(dpExample);
		for (FormAssemblyInst inst : insts) {
			RepoFormAssemblyInst rdps = new RepoFormAssemblyInst();
			BeanUtils.copyProperties(inst, rdps);
			rdps.setAssemblyId(null);
			rdps.setFormId(repoDef.getFormId());
			repoFormAssemblyInstMapper.insert(rdps);
		}
	}

	@Override
	public void pullForm(FormDef formDef, Long repoFormId) {
		RepoFormDef repoFormDef = repoFormDefMapper.selectByPrimaryKey(repoFormId);
		FormDef form = new FormDef();
		BeanUtils.copyProperties(repoFormDef, form);
		form.setFormName(formDef.getFormName());
		form.setBizId(formDef.getBizId());
		form.setBizName(formDef.getBizName());
		form.setProcDefId(formDef.getProcDefId());
		form.setProcDefName(formDef.getProcDefName());
		form.setFormId(null);
		formDefMapper.insert(form);

		// 数据集
		Example dsExample = new Example(RepoFormDataSet.class);
		Example.Criteria dsCri = dsExample.createCriteria();
		dsCri.andEqualTo("formId", repoFormId);
		List<RepoFormDataSet> dSets = repoFormDataSetMapper.selectByExample(dsExample);
		for (RepoFormDataSet ds : dSets) {
			FormDataSet rds = new FormDataSet();
			BeanUtils.copyProperties(ds, rds);
			rds.setDataSetId(null);
			rds.setFormId(form.getFormId());
			formDataSetMapper.insert(rds);
		}
		// 数据推送
		Example dpExample = new Example(RepoFormDataPush.class);
		Example.Criteria dpCri = dpExample.createCriteria();
		dpCri.andEqualTo("formId", repoFormId);
		List<RepoFormDataPush> dpSets = repoFormDataPushMapper.selectByExample(dpExample);
		for (RepoFormDataPush dps : dpSets) {
			FormDataPush rdps = new FormDataPush();
			BeanUtils.copyProperties(dps, rdps);
			rdps.setDataPushId(null);
			rdps.setFormId(form.getFormId());
			formDataPushMapper.insert(rdps);
		}

		// 表单控件
		Example assemblyExample = new Example(RepoFormDataPush.class);
		Example.Criteria assemblyCri = assemblyExample.createCriteria();
		assemblyCri.andEqualTo("formId", repoFormId);
		List<RepoFormAssemblyInst> insts = repoFormAssemblyInstMapper.selectByExample(dpExample);
		for (RepoFormAssemblyInst repoInst : insts) {
			FormAssemblyInst inst = new FormAssemblyInst();
			BeanUtils.copyProperties(repoInst, inst);
			inst.setFormId(form.getFormId());
			inst.setId(null);
			formAssemblyInstMapper.insert(inst);
		}
	}

	@Override
	public void delete(Long repoFormId) {
		// 删除组件信息
		RepoFormAssemblyInst inst = new RepoFormAssemblyInst();
		inst.setFormId(repoFormId);
		repoFormAssemblyInstMapper.delete(inst);
		// 删除输入数据
		RepoFormDataSet dataSet = new RepoFormDataSet();
		dataSet.setFormId(repoFormId);
		repoFormDataSetMapper.delete(dataSet);
		// 删除输入数据
		RepoFormDataPush dataPush = new RepoFormDataPush();
		dataPush.setFormId(repoFormId);
		repoFormDataPushMapper.delete(dataPush);
		// 移除仓库中的表单定义信息
		RepoFormDef formDef = new RepoFormDef();
		formDef.setFormId(repoFormId);
		repoFormDefMapper.delete(formDef);
	}

	@Override
	public List<RepoFormAssemblyInst> listAssemblies(Long id) {
		Example example = new Example(RepoFormAssemblyInst.class);
		Example.Criteria criteria = example.createCriteria();
		criteria.andEqualTo("formId", id);
		example.orderBy("displayOrder").asc();
		return repoFormAssemblyInstMapper.selectByExample(example);
	}

	@Override
	public Map<String, String> loadPrintForm(Long id) {
		RepoFormDef formDef = repoFormDefMapper.selectByPrimaryKey(id);
		Map<String, String> result = new HashMap<String, String>();
		result.put("fileName", formDef.getFormName());
		List<String> fileContents = jdbcTemplate.queryForList("select form_print from form_def where form_id = ?",
				String.class, id);
		byte[] fileBytes = null;
		if (null != fileContents && fileContents.size() > 0 && !StringUtils.isEmpty(fileContents.get(0))) {
			fileBytes = Base64.getDecoder().decode(fileContents.get(0));
		} else {
			// 默认显示一个空的文件
			try {
				fileBytes = IOUtils.toByteArray(
						FormDefServiceImpl.class.getClassLoader().getResourceAsStream("template/blank.doc"));
			} catch (IOException e) {
				throw new RuntimeException("读取文件失败，请检查文件是否存在", e);
			}
		}
		result.put("fileContent", Base64.getEncoder().encodeToString(WordHelper.word2Pdf(fileBytes)));
		return result;
	}

}
